﻿using System;

namespace Borg
{
    [Serializable]
    public class Slot : MetaElement
    {
        private Extension _extension;
        private SlotType _slotType;

        internal bool isOpen;

        internal bool autoOpen;
        internal bool autoPlug;
        internal string[] autoTag;

        internal bool shared;

        internal MetaElementCollection<Plug> pluggedPlugs;

        public BehaviorCollection Behaviors
        {
            get { return Notifier.GetSlotBehaviors(this); }
        }

        public Extension Extension
        {
            get { return _extension; }
            private set { _extension = value; }
        }

        public SlotType SlotType
        {
            get { return _slotType; }
            private set { _slotType = value; }
        }

        public bool AutoOpen
        {
            get { return InstanceStore.GetAutoOpen(this); }
            set { Composer.SetAutoOpen(this, value); }
        }

        public bool AutoPlug
        {
            get { return autoPlug; }
            set { Composer.SetAutoPlug(this, value); }
        }

        public string[] AutoTag
        {
            get { return autoTag; }
            set { Composer.SetAutoTag(this, value); }
        }

        public bool Shared
        {
            get { return shared; }
            set { Composer.SetShared(this, value); }
        }

        public MetaElementCollection<Plug> PluggedPlugs
        {
            get { return InstanceStore.GetPluggedPlugs(this); }
        }

        public MetaElementCollection<Tag> TaggedTags
        {
            get { return InstanceStore.GetTags(this); }
        }

        public event EventHandler<SlotEventArgs> Opening
        {
            add { Notifier.AddOpeningHandler(this, value); }
            remove { Notifier.RemoveOpeningHandler(this, value); }
        }

        public event EventHandler<SlotEventArgs> Opened
        {
            add { Notifier.AddOpenedHandler(this, value); }
            remove { Notifier.RemoveOpenedHandler(this, value); }
        }

        public event EventHandler<CompositionEventArgs> Plugging
        {
            add { Notifier.AddPluggingHandler(this, value); }
            remove { Notifier.RemovePluggingHandler(this, value); }
        }

        public event EventHandler<CompositionEventArgs> Plugged
        {
            add { Notifier.AddPluggedHandler(this, value); }
            remove { Notifier.RemovePluggedHandler(this, value); }
        }

        public event EventHandler<TagEventArgs> Tagging
        {
            add { Notifier.AddTaggingHandler(this, value); }
            remove { Notifier.RemoveTaggingHandler(this, value); }
        }

        public event EventHandler<TagEventArgs> Tagged
        {
            add { Notifier.AddTaggedHandler(this, value); }
            remove { Notifier.RemoveTaggedHandler(this, value); }
        }

        public event EventHandler<SlotEventArgs> Closing
        {
            add { Notifier.AddClosingHandler(this, value); }
            remove { Notifier.RemoveClosingHandler(this, value); }
        }

        public event EventHandler<SlotEventArgs> Closed
        {
            add { Notifier.AddClosedHandler(this, value); }
            remove { Notifier.RemoveClosedHandler(this, value); }
        }

        public event EventHandler<CompositionEventArgs> Unplugging
        {
            add { Notifier.AddUnpluggingHandler(this, value); }
            remove { Notifier.RemoveUnpluggingHandler(this, value); }
        }

        public event EventHandler<CompositionEventArgs> Unplugged
        {
            add { Notifier.AddUnpluggedHandler(this, value); }
            remove { Notifier.RemoveUnpluggedHandler(this, value); }
        }

        public event EventHandler<TagEventArgs> Untagging
        {
            add { Notifier.AddUntaggingHandler(this, value); }
            remove { Notifier.RemoveUntaggingHandler(this, value); }
        }

        public event EventHandler<TagEventArgs> Untagged
        {
            add { Notifier.AddUntaggedHandler(this, value); }
            remove { Notifier.RemoveUntaggedHandler(this, value); }
        }

        internal Slot(int id, SlotType slotType, Extension extension)
            : base(id, slotType.Name)
        {
            Extension = extension;
            SlotType = slotType;
            
            pluggedPlugs = new MetaElementCollection<Plug>();
            
            Composer.InternalSetAutoOpen(this, slotType.AutoOpen);
            Composer.InternalSetAutoPlug(this, slotType.AutoPlug);
            Composer.InternalSetAutoTag(this, slotType.AutoTag);
            Composer.InternalSetShared(this, slotType.Shared);
        }

        public bool IsOpen()
        {
            return InstanceStore.IsOpen(this);
        }

        public bool IsPlugged(Plug plug)
        {
            return InstanceStore.IsPlugged(this, plug);
        }

        public bool IsTagged(Plug plug, string tag)
        {
            return InstanceStore.IsTagged(this, plug, tag);
        }

        public void Open()
        {
            Composer.Open(this);
        }

        public void Plug(Plug plug)
        {
            Composer.Plug(this, plug);
        }

        public void Close()
        {
            Composer.Close(this);
        }

        public void Unplug(Plug plug)
        {
            Composer.Unplug(this, plug);
        }

        public void Tag(Plug plug, string tag)
        {
            Composer.Tag(this, plug, tag);
        }

        public void Untag(Plug plug, string tag)
        {
            Composer.Untag(this, plug, tag);
        }

        internal override AssemblyElement GetAssemblyElement()
        {
            return Extension.ExtensionType.Plugin;
        }
    }
}
